package com.lnsoft.dqfs.server.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lnsoft.dqfs.server.dao.ConnectArg;
import com.lnsoft.dqfs.server.handle.codec.Frame;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.Set;

public class MessageUtil {

    // 生成数据包cs验证码
    public static int createCS(byte[] bytes, int startIndex, int endIndex) {
        int cs = 0;
        for (int i = startIndex; i < endIndex; i++) {
            cs += (bytes[i] & 0xFF);
        }
        return cs & 255; // cs % 256
    }

    /**
     * 生成控制域
     *
     * @param frame
     * @param fcv
     * @param fc
     * @return
     */
    public static byte createServerC(Frame frame, byte fcv, byte fc) {
        frame.setUpServerFcb(true);
        return (byte) (64 + frame.getServerFcb() * 32 + fcv * 16 + fc);
    }


    public static byte createClientC(byte fcb, byte fcv, byte fc) {
        return (byte) (128 + 64 + fcb * 32 + fcv * 16 + fc);
    }


    /**
     * 生成 7个字节的 当前时间
     *
     * @return
     */
    public static byte[] createTimeNow() {
        LocalDateTime nowTime = LocalDateTime.now();

        int yy = nowTime.getYear() % 2000;
        int mm = nowTime.getMonth().getValue();
        int dd = nowTime.getDayOfMonth();

        int hh = nowTime.getHour();
        int mi = nowTime.getMinute();
        int sss = nowTime.getSecond() * 1000;

        byte[] bytes = new byte[7];

        ByteBuf sssbf = Unpooled.copyInt(sss);
        ByteBuf mibf = Unpooled.copyInt(mi);
        ByteBuf hhbf = Unpooled.copyInt(hh);
        ByteBuf ddbf = Unpooled.copyInt(dd);
        ByteBuf mmbf = Unpooled.copyInt(mm);
        ByteBuf yybf = Unpooled.copyInt(yy);
        try {
            bytes[0] = sssbf.getByte(3);
            bytes[1] = sssbf.getByte(2);
            bytes[2] = mibf.getByte(3);
            bytes[3] = hhbf.getByte(3);
            bytes[4] = ddbf.getByte(3);
            bytes[5] = mmbf.getByte(3);
            bytes[6] = yybf.getByte(3);
        } finally {
            sssbf.release();
            mibf.release();
            hhbf.release();
            ddbf.release();
            mmbf.release();
            yybf.release();
        }
        return bytes;
    }

    /**
     * 生成服务端认可报文
     *
     * @param a1
     * @param a2
     * @return
     */
    public static byte[] createConfirmFrame(byte a1, byte a2) {
        byte[] respBytes = new byte[]{16, 0, a1, a2, 0, 22};
        respBytes[4] = (byte) MessageUtil.createCS(respBytes, 1, 4);
        return respBytes;
    }

    /**
     * 生成服务端不认可报文
     *
     * @param a1
     * @param a2
     * @return
     */
    public static byte[] createUnConfirmFrame(byte a1, byte a2) {
        byte[] respBytes = new byte[]{16, 1, a1, a2, 0, 22};
        respBytes[4] = (byte) MessageUtil.createCS(respBytes, 1, 4);
        return respBytes;
    }

    /**
     * 单个参数读取报文
     *
     * @param frame
     * @param arg1
     * @param arg2
     * @return
     */
    public static byte[] createReadArgFrame(Frame frame, byte arg1, byte arg2) {
        byte serverC = createServerC(frame, (byte) 1, (byte) 3);
        byte[] bytes = new byte[]{104, 0, 0, 104, serverC, frame.getA1(), frame.getA2(), (byte) 202, 1, 6,
                frame.getA1(), frame.getA2(), 0, 0, arg1, arg2, 0, 22};
        return createFinallyFrame(bytes);
    }

    /**
     * 写文件激活报文
     *
     * @param fileName
     * @param size
     * @return
     */
    public static byte[] createWirteActivateFrame(Frame frame, String fileName, int size) {
        byte serverC = createServerC(frame, (byte) 1, (byte) 3);
        byte[] fileNameBytes = fileName.getBytes();

        ByteBuffer buffer = ByteBuffer.allocate(256).
                put(new byte[]{104, 0, 0, 104, serverC, frame.getA1(), frame.getA2(), (byte) 210, 1, 6,
                        frame.getA1(), frame.getA2(), 0, 0, 2, 7}).
                put((byte) fileNameBytes.length).
                put(littleStringBytes(fileName)).
                put(new byte[]{4, 0, 0, 0}).put(littleIntBytes(size)).put((byte) 0).put((byte) 22);

        buffer.flip();
        byte[] bytes = new byte[buffer.limit()];
        buffer.get(bytes);
        return createFinallyFrame(bytes);
    }

    /**
     * 升级包写文件传输报文
     *
     * @param frame
     * @param upgradePackageCache
     * @return
     */
    public static byte[] createUpgradePackageFrame(Frame frame, UpgradePackageCache upgradePackageCache) {
        byte serverC = createServerC(frame, (byte) 1, (byte) 3);
        byte[] dataBytes = upgradePackageCache.getUpgradePackageByIndex(frame.getUpgradePackageindex());
        ByteBuffer buffer = ByteBuffer.allocate(1152).
                put(new byte[]{104, 0, 0, 104, serverC, frame.getA1(), frame.getA2(), (byte) 210, 1, 6,
                        frame.getA1(), frame.getA2(), 0, 0, 2, 9, 4, 0, 0, 0}).
                put(littleIntBytes(upgradePackageCache.offset(frame)));
        //  检查下发的 报文 是否是最后一个‘升级包报文’,进行报文标识，便于终端进行识别
        if (upgradePackageCache.isReadEnd(frame.getUpgradePackageindex())) {
            buffer.put((byte) 0);
            frame.setUpgradePackageindex(-1);
        } else {
            buffer.put((byte) 1);
            frame.setUpgradePackageindex(frame.getUpgradePackageindex() + 1);
        }
        buffer.put(dataBytes);
        buffer.put((byte) MessageUtil.createCS(dataBytes, 0, dataBytes.length )).
                put((byte) 0).put((byte) 22);

        buffer.flip();
        byte[] bytes = new byte[buffer.limit()];
        buffer.get(bytes);

        //  重新设置长度位，使用小端序的两个字节作为报文长度位
        return createFinallyFrame(bytes);
//        short length = (short) (bytes.length - 6);
//        bytes[1] = (byte) (length & 0x00FF);
//        bytes[2] = (byte) (length >> 8);
//        bytes[bytes.length - 2] = (byte) createCS(bytes, 4, bytes.length - 2);
//        return bytes;
    }

    /**
     * 复位报文
     *
     * @param frame
     * @return
     */
    public static byte[] createResetFrame(Frame frame) {
        byte[] resetFrame = new byte[]{104, 0, 0, 104, createServerC(frame, (byte) 1, (byte) 3), frame.getA1(), frame.getA2(), 105, 1, 6,
                frame.getA1(), frame.getA2(), 0, 0, 1, 0, 22};
        return createFinallyFrame(resetFrame);
    }

    /**
     * 参数预置
     */
    public static byte[] createArgFrame(Frame frame, ConnectArg arg) {
//        int port = arg.getPort();
//        String ip = arg.getIp()+"."+port;
//        int connectArress = arg.getConnectArress();
        ByteBuffer buffer = ByteBuffer.allocate(256);
//        String[] ips = ip.split("\\.");
        String upArgs = arg.getUpArgs();
        JSONObject json = JSONObject.parseObject(upArgs);


        buffer.put(new byte[]{104, 0, 0, 104, createServerC(frame, (byte) 1, (byte) 3),
                frame.getA1(), frame.getA2(), (byte) 203,
                (byte)json.size(), 6,
                frame.getA1(), frame.getA2(), 1 // S/E
                , 0, (byte) 128});
        byte tag = 33;



        Set<String> set = json.keySet();
        for(String key : set){

            buffer.put(littleShortBytes(Integer.valueOf(key,16).shortValue()))
                    .put(tag)
                    .put((byte)2)
                    .put(littleShortBytes(Integer.valueOf(json.get(key).toString()).shortValue()));
        }

//        for (int i = 0; i < 5; i++) {
//            byte[] key ;
//            byte[] val;
//
//            if (connectArress == 1) {
//                key = littleShortBytes((short)(33312 + i));
//            } else {
//                key =littleShortBytes((short)(33317 + i));
//            }
//            val = littleShortBytes(Short.valueOf(ips[i]));
//            buffer.put(key).put(tag).put((byte)2).put(val);
//        }
        buffer.put((byte)0).put((byte)22);

        buffer.flip();
        byte[] bytes = new byte[buffer.limit()];
        buffer.get(bytes);
        return createFinallyFrame(bytes);
    }

    /**
     * 参数固话
     */
    public static byte[] createArgSolidifyFrame(Frame frame){
        byte[] argSolidiftFrame = new byte[]{104,0,0,104,createServerC(frame, (byte) 1, (byte) 3),
                frame.getA1(),frame.getA2(),(byte)203,0,6,frame.getA1(),frame.getA2(),0,0,0,0,22};
        return createFinallyFrame(argSolidiftFrame);
    }


    private static byte[] littleShortBytes(short val) {
        byte[] littleShortBytes = new byte[2];
        ByteBuffer shortBuffer = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(val);
        shortBuffer.flip();
        shortBuffer.get(littleShortBytes);
        return littleShortBytes;
    }


    private static byte[] littleIntBytes(int val) {
        byte[] littleIntBytes = new byte[4];
        ByteBuffer intBuffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(val);
        intBuffer.flip();
        intBuffer.get(littleIntBytes);
        return littleIntBytes;
    }


    private static byte[] littleStringBytes(String val) {
        byte[] oldBytes = val.getBytes();
        byte[] littleBytes = new byte[oldBytes.length];
        ByteBuffer buffer = ByteBuffer.allocate(oldBytes.length).order(ByteOrder.LITTLE_ENDIAN).put(oldBytes);
        buffer.flip();
        buffer.get(littleBytes);
        return littleBytes;
    }


    private static byte[] createFinallyFrame(byte[] bytes) {
        bytes[1] = bytes[2] = (byte) (bytes.length - 6);
        bytes[bytes.length - 2] = (byte) createCS(bytes, 4, bytes.length - 2);
        return bytes;
    }


    public static float upNanVal(String value) {
        if ("nan".equals(value)) {
            return 0;
        }
        return Float.valueOf(value);
    }

    public static  String asciiStr(ByteBuffer buffer,int byteSize) {
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<byteSize;i++) {
            byte b = buffer.order(ByteOrder.LITTLE_ENDIAN).get();
            if(b == 0) {
                continue;
            }
            sb.append((char)b);
        }
        return sb.toString();
    }



    public static void main(String[] args) {

//        JSONObject object = new JSONObject();
//        object.put("8220",192);
//        object.put("8221",168);
//        object.put("8222",10);
//        object.put("8223",20);
//        object.put("8224",4038);
//        System.out.println(object.size());
//        System.out.println(object.toJSONString());
//        Set<String> set = object.keySet();
//        for(String key : set){
//
//            System.out.println( Integer.valueOf(key,16) + ":" + object.get(key));
//        }



//        ByteBuffer buffer = ByteBuffer.allocate(256);
////        String[] ips = ip.split("\\.");
//        String upArgs = "{\"8222\":10,\"8223\":20,\"8220\":192,\"8221\":168,\"8224\":4038}";
//        JSONObject json = JSONObject.parseObject(upArgs);
//
//
//        buffer.put(new byte[]{104, 0, 0, 104,0,
//                0, 0, (byte) 203,
//                (byte)json.size(), 6,
//                0, 0, 1 // S/E
//                , 0, (byte) 128});
//        byte tag = 33;
//
//
//
//        Set<String> set = json.keySet();
//        for(String key : set){
//
//            buffer.put(littleShortBytes(Integer.valueOf(key,16).shortValue()))
//                    .put(tag)
//                    .put((byte)2)
//                    .put(littleShortBytes(Integer.valueOf(json.get(key).toString()).shortValue()));
//        }
//
////        for (int i = 0; i < 5; i++) {
////            byte[] key ;
////            byte[] val;
////
////            if (connectArress == 1) {
////                key = littleShortBytes((short)(33312 + i));
////            } else {
////                key =littleShortBytes((short)(33317 + i));
////            }
////            val = littleShortBytes(Short.valueOf(ips[i]));
////            buffer.put(key).put(tag).put((byte)2).put(val);
////        }
//        buffer.put((byte)0).put((byte)22);
//
//        buffer.flip();
//        byte[] bytes = new byte[buffer.limit()];
//        buffer.get(bytes);
//        byte[] bs = createFinallyFrame(bytes);
//        System.out.println(Arrays.toString(bs));
    }



}
